package com.ebo.agora.openvcall.model;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceView;

import com.ebo.agora.openvcall.ui.MainActivity;
import com.ebo.agora.propeller.Constant;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import http_utils.asynctask.HttpPostAsyncTask;
import http_utils.interfaces.IHttpPostListener;
import http_utils.utils.NetState;
import http_utils.utils.URLs;
import io.agora.openvcall.R;
import io.agora.rtc.Constants;
import io.agora.rtc.RtcEngine;
import io.agora.rtc.video.VideoCanvas;
import utils.IToast;

public class WorkerThread extends Thread {
    private final static Logger log = LoggerFactory.getLogger(WorkerThread.class);

    private final Context mContext;

    private static final int ACTION_WORKER_THREAD_QUIT = 0X1010; // quit this thread

    private static final int ACTION_WORKER_JOIN_CHANNEL = 0X2010;

    private static final int ACTION_WORKER_LEAVE_CHANNEL = 0X2011;

    private static final int ACTION_WORKER_CONFIG_ENGINE = 0X2012;

    private static final int ACTION_WORKER_PREVIEW = 0X2014;
    //LGY start
    private static final int ACTION_WORKER_STARTRECORD = 0X2015;
    private static final int ACTION_WORKER_STOPRECORD = 0X2016;
    private static final int ACTION_WORKER_GETRECORDSTATE = 0X2017;


    //LGY end

    //LGY start
//    private static final class WorkerThreadHandler extends Handler {
//
//        private WorkerThread mWorkerThread;
//
//        WorkerThreadHandler(WorkerThread thread) {
//            this.mWorkerThread = thread;
//        }
//
//        public void release() {
//            mWorkerThread = null;
//        }
//
//        @Override
//        public void handleMessage(Message msg) {
//            if (this.mWorkerThread == null) {
//                log.warn("handler is already released! " + msg.what);
//                return;
//            }
//
//            switch (msg.what) {
//                case ACTION_WORKER_THREAD_QUIT:
//                    mWorkerThread.exit();
//                    break;
//                case ACTION_WORKER_JOIN_CHANNEL:
//                    String[] data = (String[]) msg.obj;
//                    mWorkerThread.joinChannel(data[0], msg.arg1);
//                    break;
//                case ACTION_WORKER_LEAVE_CHANNEL:
//                    String channel = (String) msg.obj;
//                    mWorkerThread.leaveChannel(channel);
//                    break;
//                case ACTION_WORKER_CONFIG_ENGINE:
//                    Object[] configData = (Object[]) msg.obj;
//                    mWorkerThread.configEngine((int) configData[0], (String) configData[1], (String) configData[2]);
//                    break;
//                case ACTION_WORKER_PREVIEW:
//                    Object[] previewData = (Object[]) msg.obj;
//                    mWorkerThread.preview((boolean) previewData[0], (SurfaceView) previewData[1], (int) previewData[2]);
//                    break;
//            }
//        }
//    }


    private static final class WorkerThreadHandler extends Handler {

        private WorkerThread mWorkerThread;

        WorkerThreadHandler(WorkerThread thread) {
            this.mWorkerThread = thread;
        }

        public void release() {
            mWorkerThread = null;
        }

        @Override
        public void handleMessage(Message msg) {
            if (this.mWorkerThread == null) {
                log.warn("handler is already released! " + msg.what);
                return;
            }
            switch (msg.what) {
                case ACTION_WORKER_THREAD_QUIT:
                    mWorkerThread.exit();
                    break;
                case ACTION_WORKER_JOIN_CHANNEL:
                    String[] data2 = (String[]) msg.obj;
                    log.debug("data2[0] = " + data2[0] + " data2[1] = " + data2[1] + " data2[2] = " + data2[2] + " data2[3]= " + Integer.parseInt(data2[3]));
                    mWorkerThread.joinChannel(data2[0], data2[1], data2[2], Integer.parseInt(data2[3]));
                    break;
                case ACTION_WORKER_LEAVE_CHANNEL:
                    String channel = (String) msg.obj;
                    mWorkerThread.leaveChannel(channel);
                    break;
                case ACTION_WORKER_CONFIG_ENGINE:
                    Object[] configData = (Object[]) msg.obj;
                    mWorkerThread.configEngine((int) configData[0], (String) configData[1], (String) configData[2]);
                    break;
                case ACTION_WORKER_PREVIEW:
                    Object[] previewData = (Object[]) msg.obj;
                    mWorkerThread.preview((boolean) previewData[0], (SurfaceView) previewData[1], (int) previewData[2]);
                    break;
                case ACTION_WORKER_STARTRECORD:
                    if (Constant.UseRecord) {
                        if (str_Recording_key != null) {
                            Log.d("record key ", " = " + str_Recording_key);
                            int error = mRtcEngine.startRecordingService(str_Recording_key);
                            Log.d("record start ", "" + error);
                        }
                    }
                    break;
                case ACTION_WORKER_STOPRECORD:
                    if (Constant.UseRecord) {
                        if (str_Recording_key != null) {
                            int error = mRtcEngine.stopRecordingService(str_Recording_key);
                            Log.d("record stop ", "" + error);
                            str_Recording_key = null;
                        } else {
                            Log.d("record stop", "  ！！str_Recording_key = null ");
                        }
                    }
                    break;
                case ACTION_WORKER_GETRECORDSTATE:
                    if (Constant.UseRecord) {
                        int error = mRtcEngine.refreshRecordingServiceStatus();
                        Log.d("get record state ", " = " + error);
                    }
                    break;
            }
        }
    }


    //LGY end
    private WorkerThreadHandler mWorkerHandler;

    private boolean mReady;

    public final void waitForReady() {
        while (!mReady) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("wait for " + WorkerThread.class.getSimpleName());
        }
    }

    @Override
    public void run() {
        log.trace("start to run");
        Looper.prepare();

        mWorkerHandler = new WorkerThreadHandler(this);

        ensureRtcEngineReadyLock();

        mReady = true;

        // enter thread looper
        Looper.loop();
    }

    //LGY start
//    private RtcEngine mRtcEngine;
    private static RtcEngine mRtcEngine;

    //LGY end
    public final void enablePreProcessor() {
    }

    public final void setPreParameters(float lightness, int smoothness) {
        Constant.PRP_DEFAULT_LIGHTNESS = lightness;
        Constant.PRP_DEFAULT_SMOOTHNESS = smoothness;
    }

    public final void disablePreProcessor() {
    }
//LGY start
//    public final void joinChannel(final String channel, int uid) {
//        if (Thread.currentThread() != this) {
//            log.warn("joinChannel() - worker thread asynchronously " + channel + " " + uid);
//            Message envelop = new Message();
//            envelop.what = ACTION_WORKER_JOIN_CHANNEL;
//            envelop.obj = new String[]{channel};
//            envelop.arg1 = uid;
//            mWorkerHandler.sendMessage(envelop);
//            return;
//        }
//
//        ensureRtcEngineReadyLock();
//        mRtcEngine.joinChannel(null, channel, "OpenVCall", uid);
//
//        mEngineConfig.mChannel = channel;
//
//        enablePreProcessor();
//        log.debug("joinChannel " + channel + " " + uid);
//    }


    private void closeSelfAudioAndVideo() {
//        if(true){return;}
        if (!MainActivity.IS_CloseSelfAudioAndVideo) {
//            Toast.makeText(mContext,"打开推流",Toast.LENGTH_LONG).show();
            mRtcEngine.muteLocalAudioStream(false);
            mRtcEngine.enableLocalVideo(true);
            return;
        }
//        Toast.makeText(mContext,"关闭推流",Toast.LENGTH_LONG).show();
        mRtcEngine.muteLocalAudioStream(true);
        mRtcEngine.enableLocalVideo(false);
    }

    public final void joinChannel(String channelKey, final String channelName, String optionalInfo, int uid) {

        if (Thread.currentThread() != this) {
            str_Recording_key = null;
            log.warn("joinChannel() - worker thread asynchronously " + channelName + " " + uid);
            Message envelop = new Message();
            envelop.what = ACTION_WORKER_JOIN_CHANNEL;
            envelop.obj = new String[]{channelKey, channelName, optionalInfo, "" + uid};
            envelop.arg1 = uid;
            mWorkerHandler.sendMessage(envelop);
//            Toast.makeText(mContext, " success1 ", Toast.LENGTH_LONG).show();
            return;
        }
        int error;
        ensureRtcEngineReadyLock();
        error = mRtcEngine.joinChannel(channelKey, channelName, optionalInfo, uid);

        mEngineConfig.mChannel = channelName;

        enablePreProcessor();
        log.debug("joinChannel " + channelName + " " + uid);
//        Toast.makeText(mContext, "success2  " + error, Toast.LENGTH_LONG).show();
        log.debug(" error = " + error);
        closeSelfAudioAndVideo();
        startRecord(uid, channelName);
    }

    private static int str_uid;

    private void startRecord(int uid, String channel_name) {
        str_uid = uid;
        if (!NetState.isNetworkAvailable(mContext)) {
            IToast.show(mContext, "网络未连接!!");
            return;
        }
        Map<String, Object> postParams = new HashMap<String, Object>();
        postParams.put("uid", uid);
        postParams.put("name", channel_name);
        Log.d("getrecordkey send ", "uid= " + uid + " , channel_name=" + channel_name);
        HttpPostAsyncTask postAsyncTask = new HttpPostAsyncTask(URLs.AGORA_RECORDKEY, postParams,
                new PostListener());
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            postAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        } else {
            postAsyncTask.execute();
        }
    }

    private static String str_Recording_key;
    private static boolean is_observer;//是否旁观

    class PostListener implements IHttpPostListener {
        @Override
        public void responseSuccess(String result) {
            if (null != result) {
                try {
                    JSONObject resultObject = new JSONObject(result);
                    str_Recording_key = resultObject.getString("recording_key");
                    is_observer = resultObject.getInt("observer") == 1;
                    Log.d("getrecordkey ok ", "uid= " + str_uid + " ,result=" + result);
                    if (!is_observer) {
                        Message envelop = new Message();
                        envelop.what = ACTION_WORKER_STARTRECORD;
                        mWorkerHandler.sendMessage(envelop);
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                    Log.d("getrecordkey error ", e.toString());
                }
            }
        }

    }

    public final void leaveChannel(String channel) {

        if (Thread.currentThread() != this) {
            log.warn("leaveChannel() - worker thread asynchronously " + channel);
            Message envelop = new Message();
            envelop.what = ACTION_WORKER_LEAVE_CHANNEL;
            envelop.obj = channel;
            mWorkerHandler.sendMessage(envelop);
            return;
        }

        if (mRtcEngine != null) {
            if (!is_observer) {
                mWorkerHandler.sendEmptyMessage(ACTION_WORKER_STOPRECORD);
            }
            mRtcEngine.leaveChannel();
            mRtcEngine.enableVideo();
        }

        disablePreProcessor();

        mEngineConfig.reset();

        log.debug("leaveChannel " + channel);
    }

    //    public final void leaveChannel(String channel) {
//        if (Thread.currentThread() != this) {
//            log.warn("leaveChannel() - worker thread asynchronously " + channel);
//            Message envelop = new Message();
//            envelop.what = ACTION_WORKER_LEAVE_CHANNEL;
//            envelop.obj = channel;
//            mWorkerHandler.sendMessage(envelop);
//            return;
//        }
//
//        if (mRtcEngine != null) {
//            mRtcEngine.leaveChannel();
//            mRtcEngine.enableVideo();
//        }
//
//        disablePreProcessor();
//
//        mEngineConfig.reset();
//        log.debug("leaveChannel " + channel);
//    }
//LGY end
    private EngineConfig mEngineConfig;

    public final EngineConfig getEngineConfig() {
        return mEngineConfig;
    }

    private final MyEngineEventHandler mEngineEventHandler;

    public final void configEngine(int vProfile, String encryptionKey, String encryptionMode) {
        if (Thread.currentThread() != this) {
            log.warn("configEngine() - worker thread asynchronously " + vProfile + " " + encryptionMode);
            Message envelop = new Message();
            envelop.what = ACTION_WORKER_CONFIG_ENGINE;
            envelop.obj = new Object[]{vProfile, encryptionKey, encryptionMode};
            mWorkerHandler.sendMessage(envelop);
            return;
        }

        ensureRtcEngineReadyLock();
        mEngineConfig.mVideoProfile = vProfile;

        if (!TextUtils.isEmpty(encryptionKey)) {
            mRtcEngine.setEncryptionMode(encryptionMode);

            mRtcEngine.setEncryptionSecret(encryptionKey);
        }

//        mRtcEngine.setVideoProfile(mEngineConfig.mVideoProfile, false);
        mRtcEngine.setVideoProfile(Constants.VIDEO_PROFILE_480P, true);
//        Lg.d("configEngine " + mEngineConfig.mVideoProfile + " " + encryptionMode);
    }

    public final void preview(boolean start, SurfaceView view, int uid) {
        if (Thread.currentThread() != this) {
            log.warn("preview() - worker thread asynchronously " + start + " " + view + " " + (uid & 0XFFFFFFFFL));
            Message envelop = new Message();
            envelop.what = ACTION_WORKER_PREVIEW;
            envelop.obj = new Object[]{start, view, uid};
            mWorkerHandler.sendMessage(envelop);
            return;
        }

        ensureRtcEngineReadyLock();
        if (start) {
            mRtcEngine.setupLocalVideo(new VideoCanvas(view, VideoCanvas.RENDER_MODE_HIDDEN, uid));
//            mRtcEngine.setupLocalVideo(new VideoCanvas(view, VideoCanvas.RENDER_MODE_FIT, uid));
            mRtcEngine.startPreview();
        } else {
            mRtcEngine.stopPreview();
        }
    }

    public static String getDeviceID(Context context) {
        // XXX according to the API docs, this value may change after factory reset
        // use Android id as device id
        return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
    }

    private RtcEngine ensureRtcEngineReadyLock() {
        if (mRtcEngine == null) {
            String appId = mContext.getString(R.string.private_app_id);
            if (TextUtils.isEmpty(appId)) {
                throw new RuntimeException("NEED TO use your App ID, get your own ID at https://dashboard.agora.io/");
            }
            mRtcEngine = RtcEngine.create(mContext, appId, mEngineEventHandler.mRtcEventHandler);
            mRtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_COMMUNICATION);
            mRtcEngine.enableVideo();
            mRtcEngine.enableAudioVolumeIndication(200, 3); // 200 ms
            mRtcEngine.setLogFile(Environment.getExternalStorageDirectory()
                    + File.separator + mContext.getPackageName() + "/log/agora-rtc.log");
        }
        return mRtcEngine;
    }

    public MyEngineEventHandler eventHandler() {
        return mEngineEventHandler;
    }

    public RtcEngine getRtcEngine() {
        return mRtcEngine;
    }

    /**
     * call this method to exit
     * should ONLY call this method when this thread is running
     */
    public final void exit() {
        if (Thread.currentThread() != this) {
            log.warn("exit() - exit app thread asynchronously");
            mWorkerHandler.sendEmptyMessage(ACTION_WORKER_THREAD_QUIT);
            return;
        }

        mReady = false;

        // TODO should remove all pending(read) messages

        log.debug("exit() > start");

        // exit thread looper
        Looper.myLooper().quit();

        mWorkerHandler.release();

        log.debug("exit() > end");
    }

    public WorkerThread(Context context) {
        this.mContext = context;

        this.mEngineConfig = new EngineConfig();
        SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
        this.mEngineConfig.mUid = pref.getInt(ConstantApp.PrefManager.PREF_PROPERTY_UID, 0);

        this.mEngineEventHandler = new MyEngineEventHandler(mContext, this.mEngineConfig);
    }
}
